﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace ZoomPictureBox
{
    [ToolboxItem(true), ToolboxBitmap(typeof(ZoomPictureBox), "Icons.ZoomPictureBox.bmp")]
    public partial class ZoomPictureBox: UserControl
    {
        private Image _image;
        private PointF _panOffset = PointF.Empty;
        private float _zoom = 1.0f;
        private Point _lastPanPosition;
        private bool _isPanning;
        private Label _statusLabel;

        public Image Image
        {
            get => _image;
            set
            {
                _image?.Dispose();
                _image = value;
                ResetView();
                Invalidate();
            }
        }

        public float ZoomStep { get; set; } = 0.2f;
        public PointF PanOffset => _panOffset;
        public float Zoom => _zoom;
        public ZoomPictureBox()
        {
            InitializeComponent();

            DoubleBuffered = true;
            SetStyle(ControlStyles.OptimizedDoubleBuffer |
                    ControlStyles.UserPaint |
                    ControlStyles.AllPaintingInWmPaint, true);

            this.BorderStyle = BorderStyle.FixedSingle;

            _statusLabel = new Label
            {
                Dock = DockStyle.Bottom,
                Height = 20,
                BackColor = Color.FromArgb(240, 240, 240),
                ForeColor = Color.Black,
                TextAlign = ContentAlignment.MiddleLeft,
                Padding = new Padding(5, 0, 0, 0)
            };
            Controls.Add(_statusLabel);
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                _lastPanPosition = e.Location;
                _isPanning = true;
                Cursor = Cursors.Hand;
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (_isPanning)
            {
                Point delta = new Point(e.X - _lastPanPosition.X, e.Y - _lastPanPosition.Y);
                _panOffset.X += delta.X;
                _panOffset.Y += delta.Y;
                _lastPanPosition = e.Location;

                ClampPanOffset();
                Invalidate();
            }

            UpdateStatusBar(e.Location);
            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                _isPanning = false;
                Cursor = Cursors.Default;
            }
            base.OnMouseUp(e);
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (_image == null) return;

            PointF imagePosBeforeZoom = TransformPoint(e.Location, true);
            float newZoom = CalculateNewZoom(e.Delta);

            if (newZoom != _zoom)
            {
                _panOffset.X = e.Location.X - imagePosBeforeZoom.X * newZoom;
                _panOffset.Y = e.Location.Y - imagePosBeforeZoom.Y * newZoom;
                _zoom = newZoom;

                ClampPanOffset(); // 新增钳制偏移量
                Invalidate();
            }

            base.OnMouseWheel(e);
        }

        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                ResetView();
            }
            base.OnMouseDoubleClick(e);
        }

        private float CalculateNewZoom(int delta)
        {
            float zoomFactor = delta > 0 ? 1 + ZoomStep : 1 - ZoomStep;
            float newZoom = _zoom * zoomFactor;
            return Math.Min(Math.Max(newZoom, 0.001f), CalculateMaxZoom());
        }

        private float CalculateMaxZoom()
        {
            if (_image == null) return 1.0f;
            return Math.Min(ClientSize.Width, ClientSize.Height);
        }

        private void ClampPanOffset()
        {
            if (_image == null) return;

            float imageWidth = _image.Width * _zoom;
            float imageHeight = _image.Height * _zoom;

            // 水平方向限制：左上角X <= 控件右边界，右下角X >= 控件左边界
            float minOffsetX = -imageWidth; // 允许右下角X >= 0
            float maxOffsetX = ClientSize.Width; // 允许左上角X <= ClientSize.Width
            _panOffset.X = Clamp(_panOffset.X, minOffsetX, maxOffsetX);

            // 垂直方向限制：左上角Y <= 控件下边界，右下角Y >= 控件上边界
            float minOffsetY = -imageHeight; // 允许右下角Y >= 0
            float maxOffsetY = ClientSize.Height; // 允许左上角Y <= ClientSize.Height
            _panOffset.Y = Clamp(_panOffset.Y, minOffsetY, maxOffsetY);
        }

        private float Clamp(float value, float min, float max) =>
            value < min ? min : value > max ? max : value;

        protected override void OnPaint(PaintEventArgs e)
        {
            if (_image == null) return;

            e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
            e.Graphics.SmoothingMode = SmoothingMode.None;

            e.Graphics.TranslateTransform(_panOffset.X, _panOffset.Y);
            e.Graphics.ScaleTransform(_zoom, _zoom);
            e.Graphics.DrawImage(_image, 0, 0, _image.Width, _image.Height);
        }

        private PointF TransformPoint(Point point, bool screenToImage) =>
            screenToImage
                ? new PointF(
                    (point.X - _panOffset.X) / _zoom,
                    (point.Y - _panOffset.Y) / _zoom)
                : new PointF(
                    point.X * _zoom + _panOffset.X,
                    point.Y * _zoom + _panOffset.Y);

        public void ResetView()
        {
            if (_image != null)
            {
                _zoom = Math.Min(
                    ClientSize.Width / (float)_image.Width,
                    ClientSize.Height / (float)_image.Height
                );
                _panOffset.X = (ClientSize.Width - _image.Width * _zoom) / 2;
                _panOffset.Y = (ClientSize.Height - _image.Height * _zoom) / 2;
            }
            else
            {
                _zoom = 1.0f;
                _panOffset = PointF.Empty;
            }
            Invalidate();
        }

        private void UpdateStatusBar(Point mouseLocation)
        {
            if (_image == null) return;

            PointF imagePos = TransformPoint(mouseLocation, true);
            if (imagePos.X < 0 || imagePos.Y < 0 || imagePos.X >= _image.Width || imagePos.Y >= _image.Height)
            {
                _statusLabel.Text = "鼠标位置超出图像范围";
                return;
            }

            Color color = ((Bitmap)_image).GetPixel((int)imagePos.X, (int)imagePos.Y);
            string pixelValue = color.R == color.G && color.G == color.B
                ? $"灰度值: {color.R}"
                : $"R:{color.R}, G:{color.G}, B:{color.B}";

            _statusLabel.Text =
                $"偏移量: ({_panOffset.X:0}, {_panOffset.Y:0}) | " +
                $"缩放倍率: {_zoom:0.00}x | " +
                $"图像坐标: ({imagePos.X:0}, {imagePos.Y:0}) | " +
                pixelValue;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            ResetView();
        }

    }
}
